home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / awe / awe-full.lha / Awe2 / DoNotUseThisSrc / MultiSimMux.cc < prev    next >
C/C++ Source or Header  |  1990-08-08  |  8KB  |  364 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. // 
  3. // Copyright (C) 1988 University of Illinois, Urbana, Illinois
  4. //
  5. // written by Dirk Grunwald (grunwald@cs.uiuc.edu)
  6. //
  7.  
  8. #ifdef __GNUG__
  9. #  pragma implementation
  10. #endif
  11.  
  12. #include "MultiSimMux.h"
  13. #include "SpinLock.h"
  14. #include "SpinBarrier.h"
  15. #include "SpinFetchAndOp.h"
  16. #include "AwesimeHeap.h"
  17. #include "Thread.h"
  18.  
  19. #include "TimeSchedulerSplayPQ.h"
  20.  
  21. #include "ReserveByException.h"
  22. #include <math.h>
  23.  
  24. static SpinBarrier CpuBarrier(0);
  25.  
  26. //
  27. //    The PendingEvents queue is private to each processor
  28. //
  29.  
  30. static TimeSchedulerPQ *PendingEvents[MaxCpuMultiplexors];
  31.  
  32. static SpinLock PendingEventsLock[MaxCpuMultiplexors];
  33.  
  34. extern int CpuMuxDebugFlag;
  35.  
  36. MultiSimMux::MultiSimMux(int debug, int spinMax)
  37.     : SimulationMultiplexor(debug), MultiCpuMux(debug)
  38. {
  39.  
  40.     ThisSimulationMultiplexor = this;
  41.     ThisCpu = this;
  42.  
  43.     CpuMuxDebugFlag = debug;
  44.     
  45.     pNameTemplate = "SimMux";
  46.     cpuBarrier = &CpuBarrier;
  47.     CpuBarrier.maxLoops(spinMax);
  48.  
  49.     sprintf(nameSpace, "[%s-%d] ", pNameTemplate, MultiCpuMux::iYam);
  50.     pName = nameSpace;
  51.  
  52.     MultiCpuMux::allocateLocalEventStructures(0,1);
  53.     MultiSimMux::allocateLocalEventStructures(0,1);
  54. }
  55.  
  56. void
  57. MultiSimMux::allocateLocalEventStructures(int newIYam, int outOf)
  58. {
  59. #ifndef NDEBUG
  60.     if (CpuMuxDebugFlag) {
  61.     CpuCerrLock.reserve();
  62.     cerr << name() << "Allocate SimMux structures for " << newIYam << "\n";
  63.     CpuCerrLock.release();
  64.     }
  65. #endif /* NDEBUG */
  66.  
  67.     PendingEvents[newIYam] = new TimeSchedulerSplayPQ;
  68.  
  69.     myPendingEvents = PendingEvents[newIYam];
  70.     myPendingEventsLock = &PendingEventsLock[newIYam];
  71.  
  72. #ifndef NDEBUG
  73.     if (CpuMuxDebugFlag) {
  74.     CpuCerrLock.reserve();
  75.     cerr << name() << "set CpuBarrier height to " << outOf << "\n";
  76.     CpuCerrLock.release();
  77.     }
  78. #endif /* NDEBUG */
  79.     CpuBarrier.height( outOf );
  80. }
  81.  
  82. void
  83. MultiSimMux::allocateEventStructures(int newIYam, int outOf)
  84. {
  85.     CpuCerrLock.reserve();
  86.     cerr << name() << " enter allocateEventStructures, call local\n";
  87.     CpuCerrLock.release();
  88.  
  89.     allocateLocalEventStructures(newIYam, outOf);
  90.  
  91.     //
  92.     // must do this after the local structures get set up so that
  93.     // CpuMultiplexors does not increase until all data structures are
  94.     // in place, otherwise people may poke at them before theyre set up.
  95.     //
  96.  
  97.     // CpuMultiplexor::allocateEventStructures(newIYam, outOf);
  98. }
  99.  
  100. void
  101. MultiSimMux::deallocateEventStructures()
  102. {
  103.  
  104.     // CpuMultiplexor::deallocateEventStructures();
  105.  
  106. #ifndef NDEBUG
  107.     if (CpuMuxDebugFlag) {
  108.     CpuCerrLock.reserve();
  109.     cerr << name() << "Deallocate SimMux structures for" << MultiCpuMux::iYam << "\n";
  110.     CpuCerrLock.release();
  111.     }
  112. #endif /* NDEBUG */
  113.  
  114.     PendingEventsLock[0].reserve();
  115.  
  116.     while ( ! myPendingEvents -> empty() ) {
  117.     assert( MultiCpuMux::iYam != 0 );
  118.     TimeScheduler& item = myPendingEvents -> front();
  119.     PendingEvents[0] -> enq( item );
  120.     myPendingEvents -> del_front();
  121.     }
  122.  
  123.     PendingEventsLock[0].release();
  124.  
  125.     delete myPendingEvents;
  126.     myPendingEvents = 0;
  127.     PendingEvents[ MultiCpuMux::iYam ] = 0;
  128.  
  129. #ifndef NDEBUG
  130.     if (CpuMuxDebugFlag) {
  131.     CpuCerrLock.reserve();
  132.     cerr << name() << "set CpuBarrier height to " << CpuMultiplexors << "\n";
  133.     CpuCerrLock.release();
  134.     }
  135. #endif /* NDEBUG */
  136.     CpuBarrier.height(CpuMultiplexors);
  137. }
  138.  
  139. void
  140. MultiSimMux::fireItUp( int cpus, unsigned shared )
  141. {
  142.  
  143. #ifndef NDEBUG
  144.     if (CpuMuxDebugFlag) {
  145.     CpuCerrLock.reserve();
  146.     cerr << name() << "Allocate " << shared << " bytes of shared memory\n";
  147.     CpuCerrLock.release();
  148.     }
  149. #endif /* NDEBUG */
  150.  
  151.     if ( cpus > 1 ) {
  152.     extern void SharedMemoryInit( unsigned );
  153.     SharedMemoryInit( shared );
  154.     }
  155.  
  156.     cerr << "in MultiSimMux::fireItUp, call warm\n";
  157.     warmThePot( cpus );
  158.     cerr << "in MultiSimMux::fireItUp, call stir\n";
  159.     stirItAround();
  160.     cerr << "in MultiSimMux::fireItUp, call cool\n";
  161.     coolItDown();
  162. }
  163.  
  164. void
  165. MultiSimMux::warmThePot(int cpus)
  166. {
  167.     
  168.     if ( cpus > MaxCpuMultiplexors ) {
  169.     cpus = MaxCpuMultiplexors;
  170.     }
  171.  
  172.     CpuBarrier.height(cpus);
  173. //    multiCpu.warmThePot(cpus);
  174.     MultiCpuMux::warmThePot(cpus);
  175.     int ok = CpuBarrier.rendezvous();
  176. #ifndef NDEBUG
  177.     if (! ok ) {
  178.     CpuCerrLock.reserve();
  179.     cerr << name() << "barrier overrun\n";
  180.     CpuCerrLock.release();
  181.     }
  182. #endif
  183. }
  184.  
  185. void
  186. MultiSimMux::stirItAround()
  187. {
  188.     while( ! *(MultiCpuMux::terminated) ) {
  189.     MultiCpuMux::stirItAround();
  190.     if (! *(MultiCpuMux::terminated) ) {
  191.         int tasks = advanceTime();
  192. #ifndef NDEBUG
  193.         if ( CpuMuxDebugFlag && tasks < 1 ) {
  194.         CpuCerrLock.reserve();
  195.         cerr << name() << "nothing to do, hang out\n";
  196.         CpuCerrLock.release();
  197. #endif
  198.         }
  199.     }
  200.     }
  201. }
  202.  
  203. void
  204. MultiSimMux::coolItDown()
  205. {
  206.     CpuBarrier.rendezvous();
  207.     MultiCpuMux::coolItDown();
  208.     //
  209.     //  In case we call rendezvous again
  210.     //
  211.     CpuBarrier.height(CpuMultiplexors);
  212. }
  213.  
  214. //
  215. //    Advance time. Assumes all other CPUs are idle, so no locking
  216. //    on event structures is needed.
  217. //
  218. int
  219. MultiSimMux::advanceTime()
  220. {
  221.     //
  222.     //    If, for some reason, we fail to rendezvous after the timeout,
  223.     //  click on debug output.
  224.     //
  225.  
  226.     int ok = CpuBarrier.rendezvous();
  227.  
  228. #ifndef NDEBUG
  229.     if ( !ok ) {
  230.     int oldFlag = CpuMuxDebugFlag;
  231.  
  232.     CpuMuxDebugFlag = 1;
  233.     CpuCerrLock.reserve();
  234.     cerr << name() << "rendezvous fails, enable debugging\n";
  235.     CpuCerrLock.release();
  236.     while ( ! CpuBarrier.rendezvous() );
  237.  
  238.     CpuMuxDebugFlag = oldFlag;
  239.     CpuCerrLock.reserve();
  240.     cerr << name() << "rendezvous resumes, reset debugging\n";
  241.     CpuCerrLock.release();
  242.     }
  243. #endif /* NDEBUG */
  244.  
  245.     
  246.     //
  247.     // Nothing is locked at this point.
  248.     //
  249.     
  250.     if ((MultiCpuMux::iYam) == 0) {
  251. #ifndef NDEBUG
  252.     if (CpuMuxDebugFlag) {
  253.         CpuCerrLock.reserve();
  254.         cerr << name() << "Scan " << CpuMultiplexors << " for pending\n";
  255.         CpuCerrLock.release();
  256.     }
  257. #endif /* NDEBUG */
  258.     
  259.     //
  260.     // Find the minimum time over all pending event piles
  261.     //
  262.     double when = MAXFLOAT;
  263.     bool validItem = FALSE;
  264.     for (int i = 0; i < CpuMultiplexors; i++ ) {
  265.         TimeSchedulerPQ *p = PendingEvents[i];
  266.         if ( ! p -> empty() ) {
  267.         double hapAt = (p -> front()).time();
  268.         if (hapAt < when) {
  269.             when = hapAt;
  270.             validItem = TRUE;
  271.         }
  272.  
  273. #ifndef NDEBUG
  274.         if (CpuMuxDebugFlag) {
  275.             CpuCerrLock.reserve();
  276.             cerr << name() << i;
  277.             cerr << " has one at " << hapAt << "\n";
  278.             CpuCerrLock.release();
  279.         }
  280. #endif /* NDEBUG */
  281.         }
  282. #ifndef NDEBUG
  283.         else {
  284.         if (CpuMuxDebugFlag) {
  285.             CpuCerrLock.reserve();
  286.             cerr << name() << i << " has nothing\n";
  287.             CpuCerrLock.release();
  288.         }
  289.         }
  290. #endif /* NDEBUG */
  291.     }
  292.     
  293.     if ( !validItem ) {
  294. #ifndef NDEBUG
  295.         if (CpuMuxDebugFlag) {
  296.         CpuCerrLock.reserve();
  297.         cerr << name() << " Unable to advance time, exit \n";
  298.         CpuCerrLock.release();
  299.         }
  300. #endif /* NDEBUG */
  301.         *(MultiCpuMux::terminated) = 1;
  302.     }
  303.     else {
  304.         
  305. #ifndef NDEBUG
  306.         if (CpuMuxDebugFlag) {
  307.         CpuCerrLock.reserve();
  308.         cerr << name() << " ADVANCE TIME TO " << when << "\n" ;
  309.         CpuCerrLock.release();
  310.         }
  311. #endif /* NDEBUG */
  312.         
  313.         assert( CurrentSimulatedTime <= when );
  314.         CurrentSimulatedTime = when;
  315.     }
  316.     }
  317.     
  318.     CpuBarrier.rendezvous();
  319.     
  320.     //
  321.     // Now that we know the time of the minimum entry in the
  322.     // heap, remove all the events which occur at that time
  323.     // or before that time (actually, that is an error).
  324.     //
  325.     // Each process does its own work to reduce overhead.
  326.     // We keep track of how many processes were added to
  327.     // the current events queue and then bump the global
  328.     // events count by that amout.
  329.     //
  330.     // This cannot cause race conditions because we only
  331.     // use this info in the rendevzous to advance time
  332.     // code above, and not all cpus will be there yet
  333.     // (i.e. the current cpu is not there)
  334.     //
  335.     int added = 0;
  336.     
  337.     MultiCpuMux::myCurrentEventsLock -> reserve();
  338.  
  339.     TimeSchedulerPQ *p = myPendingEvents;
  340.     while ( ! p -> empty() ) {
  341.     TimeScheduler &item = p -> front();
  342.     if ( item.time() > CurrentSimulatedTime )
  343.         break;
  344.     MultiCpuMux::addUnlocked( item.thread() );
  345.     added++;
  346.     p -> del_front();
  347.     } 
  348.     
  349.     *(MultiCpuMux::myCurrentEventsCounter) += added;
  350.     MultiCpuMux::myCurrentEventsLock -> release();
  351.  
  352.     MultiCpuMux::globalCurrentEventsCounter -> add(added);
  353.     
  354. #ifndef NDEBUG
  355.     if ( CpuMuxDebugFlag ) {
  356.     CpuCerrLock.reserve();
  357.     cerr << name() << " added " << added << " threads to current";
  358.     cerr << ", leaving me " << myPendingEvents -> length() << "\n";
  359.     CpuCerrLock.release();
  360.     }
  361. #endif
  362.     return(added);
  363. }
  364.